--
-- Created by IntelliJ IDEA.
-- User: bluda
-- Date: 2018/8/20
-- Time: 15:44
-- To change this template use File | Settings | File Templates.
-- 战斗单元

local ORDER_MOVE = 1
local ORDER_ATTACK = 2
local ORDER_STAND = 3

local MotionStreak = cc.MotionStreak


local FightUnit = {
    id = nil,
    hp = 100,
    maxHp = 100,
    fightValue = 100,
    attackMode = FAR_ATTACK,
    attackWay = "dao1",
    attackValue = math.random(2, 18),
    attackDistance = math.random(50, 10),
    attackSpeed = math.random(0.1, 2.0),
    moveSpeed = math.random(30, 120),
    type = 0,       -- 0 君主，1 武将， 2 士兵， 3 建筑物
    defence = 5,
    name = "战斗单元",
    classify = "bubing",
    leaveBattle = false,
    weight = 1,
    killCount = 0,
    position = {x=0, y=0},
    faceDirection = 0,
    target = nil,
    grid = {r=0,c=0},
    state = "alive",
    shape = 1, -- 体型大小
    
    -- 游戏控制
    moveTime = 0,
    anim = {},
    animSpeed = 1/8,
    currentAnim = nil,
    attackTime = 0,
    -- 操作指令，前往，攻击，待命
    orders = {}, 
    -- 是否人工接管，默认是系统接管，自动战斗，人工接管后，只能挨打, ！！！没实现
    manual = false,
    acting = false,
    
    -- 战场
    battlefield = nil,
    -- 所属军队
    military = nil,
    -- 所属中队
    squad = nil,
}


-- 右移动
function FightUnit:playMove()
    if self.currentAnim == self.anim.moveFrames then
        return    
    end
    
    self.currentAnim = self.anim.moveFrames
    -- 刷新动画
    self:refreshCurrentAnimUI()
end

-- 站立
function FightUnit:stand()
    if self.currentAnim == self.anim.standFrames then
        return
    end

    self.orders = {}
    
    self.currentAnim = self.anim.standFrames
    -- 刷新动画
    self:refreshCurrentAnimUI()
end

-- 得到综合移动速度
function FightUnit:getMoveSpeed()
    return self.moveSpeed    
end

-- 每次进入操作都判断自己是否死亡
function FightUnit:checkDead()
    if self.hp <= 0 then
        self.deadTime = os.clock()
        self.state = "dead"
        self.battlefield:clearSelfGrid(self)
        return true
    end
    
    return false
end

-- 每一帧处理
function FightUnit:process(dt, ct, ci)
    if not self:isValid() then
        logD("dead or leave!!!!", self.state, self.leaveBattle)
        if os.clock() - self.deadTime > 5 then
            self.military:cleanUnit(self)
        end
        
        return
    end

    -- 判断自己是否已经死亡
    if self:checkDead() then
        self:playDeadUI()
        return
    end

    if self.acting == false then
        -- 遍历orders
        local currentOrder = self.orders[1]
        if currentOrder == nil then
            -- 没有命令  
            -- 启动ai
            self:aiProcess(dt, ct, ci)
        else
            -- 处理命令
            self:orderProcess(currentOrder, dt, ct, ci)
        end
    end

    self:localProcess(dt, ct, ci)

    self:resetZOrder()
    self.moveTime = ct
end

function FightUnit:localProcess(dt, ct, ci)
    
end

function FightUnit:aiProcess(dt, ct, ci)
    local target = self.target
    if target == nil or not target:isValid() then
        -- 目标无效
        -- 移除当前order
        self.target = nil
        --self:stand()    
    else
        local inAttackArea = self:isTargetInAttackArea(target)
        if inAttackArea then
            self:attack(target, dt, ct, ci)
        else
            self:moveTo(target.position, dt, ct, ci)
        end
    end

    -- 找目标
    self:autoFindTarget()
end

function FightUnit:orderProcess(order, dt, ct, ci)
    if order.type == ORDER_MOVE then
        local canReach = self:moveTo(order.position, dt, ct, ci)
        if canReach == false then
            table.remove(self.orders, 1) 
        end
    elseif order.type == ORDER_ATTACK then
        self:attackOrderProcess(order, dt, ct, ci)
    elseif order.type == ORDER_STAND then
        self:stand()
        self.orders = {}
    end
end

-- 瞬间移到目的
function FightUnit:moveBy(x, y)
    local bf = self.battlefield
    bf:clearSelfGrid(self)
    self.faceDirection = x / math.abs(x)
    self:playMove()
    self.position.x = self.position.x + x
    self.position.y = self.position.y + y
    self.ui:setPosition(self.position)
    self.grid.c, self.grid.r = bf:resetSelfGrid(self)
end

function FightUnit:moveTo(position, dt, ct, ci)
    local bf = self.battlefield
    local pc, pr = bf:clearSelfGrid(self)

    local grid = {}
    grid.c, grid.r = bf:getGridByPosition(position)

    -- 如果垂直夹角太小，忽略垂直
    local xDistance = 0
    local yDistance = 0
    --local angle = angleY(target.position, self.position)


    self.faceDirection = self:getTargetDirection(position)
    self:playMove()

    -- 如果这次移动 能超过剩下的距离，那么直接到达终点
    local envEffect = self.battlefield:getEnvEffect(self.position)
    local dist = dt * self.moveSpeed * (1 - envEffect.msd)
    if dist > distance(self.position, position) then
        self.position.x = position.x
        self.position.y = position.y

        self.ui:setPosition(self.position)
        self.grid.c, self.grid.r = bf:resetSelfGrid(self)
    
        return false
    else
--        local angle = FindPath:find(self, position, grid, bf:getGridMap())
        local ang= angle(self.position, position)
        if ang == nil then
            -- 无法抵达
            return false
        end
        
        -- 得到地形影响 
        xDistance = dt * self.moveSpeed * math.cos(ang/180 * 3.1415) * (1 - envEffect.msd)
        yDistance = dt * self.moveSpeed * math.sin(ang/180 * 3.1415) * (1 - envEffect.msd)

        if xDistance == 0 and yDistance == 0 then
            return true
        end

        local xAdd = self.position.x + xDistance
        local yAdd = self.position.y + yDistance

        local size = self.battlefield.size
        --logD("xAdd, yAdd)
        if xAdd < 0 then
            -- TODO 走到左头
            return false
        end

        if xAdd > size.width then
            -- TODO 走到右头
            return false
        end

        self.position.x = xAdd
        self.position.y = yAdd

        self.ui:setPosition(self.position)
        self.grid.c, self.grid.r = bf:resetSelfGrid(self)
    end
    
    return true
end

function FightUnit:attackOrderProcess(order, dt, ct, ci)
    local target = order.target
    if target == nil or not target:isValid() then
        -- 目标无效
        -- 移除当前order
        self.target = nil
        table.remove(self.orders, 1)
        return
    end

    local inAttackArea = self:isTargetInAttackArea(target)
    if inAttackArea then
        self:attack(target, dt, ct, ci)
    else
        self:moveTo(target.position, dt, ct, ci)
    end
end

function FightUnit:resetZOrder()
    -- 设置zorder
    local y = math.floor(self.position.y)
    
    self.ui:setLocalZOrder(self.battlefield.size.height - y)
    local radio = 1 - (y * 0.3) / self.battlefield.size.height
    logD("reset z order " , y , radio)

    self.ui:setScale(radio * self.faceDirection * self.shape, radio * self.shape)
end

-- 目标是否在攻击范围
function FightUnit:isTargetInAttackArea(target)
    if self.attackDistance >= math.abs(self.grid.r - target.grid.r) 
            and self.attackDistance >= math.abs(self.grid.c - target.grid.c) then -- distance(self.position, target.position) then
        return true
    end
    
    return false
end

-- 得到目标方向
function FightUnit:getTargetDirection(position)
    if position.x >= self.position.x then
        return FACE_RIGHT
    end
    return FACE_LEFT
end

function FightUnit:isAlive() 
    return self.state ~= "dead"    
end

function FightUnit:isLeaveBattle()
    return self.leaveBattle
end

function FightUnit:isValid() 
    return self:isAlive() and (not self:isLeaveBattle())
end

-- 找到一个目标
function FightUnit:autoFindTarget()
    -- 得到敌方阵营
    local targetMly = self.military:getTargetMilitary()
    
    -- 找到一个离我最近的目标
    local targetUnits = targetMly:getKeyUnits()
    local nearestDistance = -1

    if self.target ~= nil then
        nearestDistance = distance(self.position, self.target.position)
    end

    -- 寻找目标卡顿,3次离散寻找
    local counter = #targetUnits
    if #targetUnits > 3 then
        counter = 3        
    end
    for i = 1, counter do
        local index = math.random(1, #targetUnits)
        local targetUnit = targetUnits[index]
        local distance = distance(self.position, targetUnit.position) 
        if (nearestDistance == -1 or distance < nearestDistance) and targetUnit:isValid() then
            nearestDistance = distance
            self.target = targetUnit
            if i == counter then
                break
            end
        end
    end
    local targetName = "nil"
    if self.target ~= nil then
        targetName = self.target.name
        --self:attackOrder(self.target)
    end
    
    logD(self.name .. " 目标 " .. targetName)
end

function FightUnit:gridValue()
    return self.battlefield:getGridValue(self.position)
end

-- 攻击
function FightUnit:attack(target, dt, ct, ci)
    local envEffect = self.battlefield:getEnvEffect(self.position)
    if ct - self.attackTime < self.attackSpeed * (1 + envEffect.asd)then
        return
    end

    self.faceDirection = self:getTargetDirection(target.position)
    self:playAttackUI()
    --target:playHitUI()
    --logW(self.name .. " 攻击 " .. target.name)
    if self.attackMode == FAR_ATTACK then
        self:createAttackUnit(ct, ci, envEffect)
    else
        self:attackCalculate(ct, ci, envEffect)
    end

    self.attackTime = ct
end

function FightUnit:createAttackUnit(ct, ci, envEffect)
    local mt = MotionStreak:create(0.3, 10, 1.0, cc.c3b(186, 186, 186), "streak.png")
    local av = self.attackValue * (1 - envEffect.avd)
    local au = AttackUnit:create(self.battlefield, ct, self.attackWay, av, 450, false, mt
        , self.target, self.position, self.target.position, 100, nil)
    self.battlefield:addAttackUnit(au)
end

-- 攻击数值计算
function FightUnit:attackCalculate(ct, ci, envEffect)
    -- 处理数值
    local target = self.target
    local av = self.attackValue * (1 - envEffect.avd)
    local targetEnv = self.battlefield:getEnvEffect(target.position)
    target.hp = target.hp - (av / (target.defence *(1 - targetEnv.dsd))+ av / 2)
    if target.hp < 0 then
        target.hp = 0
    end
    --logI(self.name .. " 攻击 " .. target.name .. " : -" .. self.attackValue , target.hp)
end


function FightUnit:playAttackUI()
    -- 攻击乙方攻击动画
    --logI(self.name ..  " playAttackUI")
    local animation
    if self.attackSpeed > 0.5 then
        animation = display.newAnimation(self.anim.attackFrames, 0.2 / ANIM_FRAMES)
    else
        animation = display.newAnimation(self.anim.attackFrames, self.attackSpeed / ANIM_FRAMES)
    end
    animation:setRestoreOriginalFrame(false)

    local anim = cc.Animate:create(animation)
    self.acting = true
    local act = cc.Sequence:create(anim, cc.CallFunc:create(function()
        self.currentAnim = self.anim.standFrames
        self:refreshCurrentAnimUI()
        self.acting = false
    end))
    self.ui:stopAllActions()
    self.ui:runAction(act)
end

-- 被攻击动画
function FightUnit:playHitUI()
    --logI(self.name .. " playHitUI")

    local animation = display.newAnimation(self.anim.hitFrames, self.animSpeed)
    animation:setRestoreOriginalFrame(false)
    local anim = cc.Animate:create(animation)
    self.ui:stopAllActions()
    self.ui:runAction(anim)
end

function FightUnit:playDeadUI()
    --logI(self.name .. " playDeadUI")

    local animation = display.newAnimation(self.anim.deadFrames, self.animSpeed)
    animation:setRestoreOriginalFrame(false)
    local anim = cc.Animate:create(animation)
    self.ui:stopAllActions()
    self.ui:runAction(anim) 
end


-- 刷新当前动画
function FightUnit:refreshCurrentAnimUI()
    local animation = display.newAnimation(self.currentAnim, self.animSpeed)
    animation:setRestoreOriginalFrame(false)
    local anim = cc.Animate:create(animation)
    self.ui:stopAllActions()
    self.ui:runAction(cc.RepeatForever:create(anim))
    self:resetZOrder()
end

-- 把UI加到哪一个节点
function FightUnit:addToUI(node) 
    self.ui:setPosition(self.position):addTo(node)
end

-- 构造一个战斗基本单元
function FightUnit:create(battlefield, military, name)
    local unit = xcopy(FightUnit)
    unit.id = military:getAllUnitCount() .. "_" .. military:getId()
    
    
    unit.name = name
    unit.battlefield = battlefield
    unit.military = military

    unit.moveTime = os.clock()
    unit.attackTime = os.clock()
    unit.faceDirection = FACE_RIGHT

    return unit
end

-- 设置位置
function FightUnit:setPosition(x, y)
    self.position.x = x
    self.position.y = y
    local bf = self.battlefield

    self.grid.c, self.grid.r = bf:resetSelfGrid(self)
end

-- 初始化资源
function FightUnit:initUI(prefiex, rightStandRes, rightMoveRes, rightAttackRes, rightHitRes, rightDeadRes, attackAnimation)
    self.ui = display.newSprite()
    self.ui:setAnchorPoint(0.5, 0.5)

    if self.hp >= 1000 then
    end
    
    logI(prefiex, rightStandRes, rightMoveRes, rightAttackRes, rightHitRes, rightDeadRes)
    self.anim.standFrames = display.newFrames(prefiex .. "/stand/" .. rightStandRes .. "_%d.png", 0, 8, false)
    self.anim.moveFrames = display.newFrames(prefiex .. "/move/" .. rightMoveRes .. "_%d.png", 0, 8, false)
    self.anim.attackFrames = display.newFrames(prefiex .. "/attack/" .. rightAttackRes .. "_%d.png", 0, 8, false)
    self.anim.hitFrames = display.newFrames(prefiex .. "/stand/" .. rightHitRes .. "_%d.png", 0, 8, false)
    self.anim.deadFrames = display.newFrames(prefiex .. "/dead/" .. rightDeadRes .. "_%d.png", 0, 8, false)

    if attackAnimation ~= nil then
        spriteFrame:addSpriteFrames("fight/" .. attackAnimation .. ".plist")
        self.anim.attackEffectFrames = display.newFrames(attackAnimation, 0, 7, false)
    end

    self:resetZOrder()
end

-- 添加攻击指令
function FightUnit:attackOrder(target)
    self.manual = true
    self.orders[1] =  {type=ORDER_ATTACK, target=target}
    --table.insert(self.orders, 1, {type=ORDER_ATTACK, target=target})
end

-- 移动指令
function FightUnit:moveOrder(position)
    self.manual = true
    local target = nil--self.battlefield:chooseUnit(position)
    if target ~= nil then
        self.orders[1] =  {type=ORDER_ATTACK, target=target}
    else
        self.orders[1] =  {type=ORDER_MOVE, position=position }
    end
--    table.insert(self.orders, 1, {type=ORDER_MOVE, position=position})
end


function FightUnit:standOrder()
    self.manual = false
    self.orders[1] =  {type=ORDER_STAND}
--    table.insert(self.orders, 1, {type=ORDER_STAND})
end

function FightUnit:freeAttack()
    
end


return FightUnit